package p2p;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.rmi.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import server.Message;

public class PeerPool{
	private List<Peer> plist = new CopyOnWriteArrayList<Peer>();
	private Peer thisPeer;

	public PeerPool(Peer thisPeer) {
		this.thisPeer = thisPeer;
	}

	public void hello(Peer fromPeer, int ttl){
		Registry registry;
		Message rmiServer;

		/*
		 * TTL
		 */
		if(ttl <= 0) return;

		/*
		 * Add to own peerpool
		 */
		add(fromPeer);

		/*
		 * Acknowledge hello
		 */
		try {
			registry = LocateRegistry.getRegistry(fromPeer.getIp(), fromPeer.getPort()); //get the “registry” 
			rmiServer = (Message)(registry.lookup(Config.ServerName)); //look up remote object
			rmiServer.ackHello(this.thisPeer); //call remote method
		}catch (ConnectException e) { // Klienten kan være offline!!!
			System.out.println("Connection refused to host: "+fromPeer.getIp()+":"+fromPeer.getPort());
		} catch (NotBoundException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		}

		/*
		 * Send hello to peerPool
		 */
		for(Peer p : plist) {
			try{
				registry = LocateRegistry.getRegistry(p.getIp(), p.getPort()); //get the “registry” 
				rmiServer = (Message)(registry.lookup(Config.ServerName)); //look up remote object
				rmiServer.hello(fromPeer, ttl-1); //call remote method
			}catch (ConnectException e) { // Klienten kan være offline!!!
				remove(p);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void ackHello(Peer fromPeer) {
		add(fromPeer);
	}

	public void isAlive() {
		//do nothing
	}

	public void update() {
		Registry registry;
		Message rmiServer;

		for(Peer p : plist) {
			try {
				registry = LocateRegistry.getRegistry(p.getIp(), p.getPort()); //get the “registry” 
				rmiServer = (Message)(registry.lookup(Config.ServerName)); //look up remote object
				rmiServer.isAlive(); //call remote method
			}catch (ConnectException e) { // Klienten kan gå offline lige efter den har sendt beskeden!!
				remove(p);
			} catch (RemoteException e) {
				remove(p);
			} catch (NotBoundException e) {
				remove(p);
			}
		}
		
		if(plist.size() <= Config.MinNumberOfPeersInPlist) {
			for(Peer p : plist) {
				try {
					registry = LocateRegistry.getRegistry(p.getIp(), p.getPort()); //get the “registry” 
					rmiServer = (Message)(registry.lookup(Config.ServerName)); //look up remote object
					rmiServer.hello(thisPeer, Config.TTL); //call remote method
				} catch(ConnectException e) {
				} catch (RemoteException e) {
				} catch (NotBoundException e) {
				}
			}
		}
	}

	@Override
	public String toString() {
		String res = "";

		if(plist.isEmpty()) return "empty!";

		for(Peer p : plist) {
			res += p.toString() + "\n";
		}

		return res;
	}

	public Peer getPeerFromName(String name) {
		for(Peer p : plist) {
			if(name.equals(p.getName())) { //name == p.name?
				return p;
			}
		}
		return null;
	}

	public List<Peer> getPeerPoolList(){
		List<Peer> plistClone = new ArrayList<Peer>();
		plistClone.addAll(plist);
		return plistClone;
	}

	/*
	 * Private methods
	 */
	private void add(Peer p) {
		if(!plist.contains(p)&&!p.equals(thisPeer)) {
			plist.add(p);
		}
	}

	private void remove(Peer p){
		this.plist.remove(p);
	}

}